Fork me on GitHub

设计模式 - 单例

注意:所有文章除特别说明外,转载请注明出处.

简介

该类型模式属于创建型模式,提供了一种创建对象的最佳方式。该模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。此类提供一种访问其唯一的对象的方式,可直接访问,不需要实例化该类对象。

注意:1.单例类只能有一个实例 2.单例类必须自己创建自己的唯一实例 3.单例类必须给所有其它对象提供这一实例

单例模式的优点:

1. 对于频繁使用的对象,可以省略new操作花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销。

2. 由于new操作的次数减少,因为对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。

单例模式的具体实现

1.创建Singleton类

public class SingleObject {

   //创建 SingleObject 的一个对象
   private static SingleObject instance = new SingleObject();

   //让构造函数为 private,这样该类就不会被实例化 new Singleton()
   private SingleObject(){}

   //获取唯一可用的对象
   public static SingleObject getInstance(){
      return instance;
   }

   public void showMessage(){
      System.out.println("Hello World!");
   }
}

2.从新创建的Singleton类获取唯一对象

public class SingletonPatternDemo {
    public static void main(String[] args){
          //不合法的构造函数
          //编译时错误:构造函数 SingleObject() 是不可见的
          //SingleObject object = new SingleObject();

          //获取唯一可用的对象
          SingleObject object = SingleObject.getInstance();

          //显示消息
          object.showMessage();
    }
}

单例模式的几种实现方式

1.懒汉式(线程不安全)

这种方式是基本的实现方式,但是此实现不支持多线程,因为没有加锁synchronized。

public class Singleton {  
    private static Singleton instance; 
    //堵死 new Singleton() 路
    private Singleton (){}  

    public static Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}

2.懒汉式(线程安全)

这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是效率很低。必须加锁 synchronized 才能保证单例,但加锁会影响效率。

public class Singleton {  
    private static Singleton instance;  

    //堵死 new Singleton() 路
    private Singleton (){}  

    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}

3.饿汉式

该模式先将单例进行实例化,获取的时候通过静态方法直接获取即可。缺点是类加载后就完成了类的实例化,浪费部分空间。这种方式常用,但是容易产生垃圾对象,这种方式没有加锁,执行效率很高。但是在类加载时就初始化,浪费内存。

public class Singleton {  
    //这一句是饿汉模式的核心
    private static Singleton instance = new Singleton();  

    private Singleton (){}  

    public static Singleton getInstance() {  
    return instance;  
    }  
}

4.双检锁/双重校验锁(DCL double-checked locking)

这种方式采用双锁机制,安全且在多线程情况下能保持高性能。

public class Singleton { 
    //采用volatile修饰单例,然后通过一次检查判断单例是否初始化
    private volatile static Singleton singleton;  

    private Singleton (){}  
    public static Singleton getSingleton() {  
        if (singleton == null) {  
            synchronized (Singleton.class) {  
            if (singleton == null) {  
                singleton = new Singleton();  
            }  
        }  
    }  
    return singleton;  
    }  
}

5.登记式/静态内部类

这种方式能达到双检锁方式一样的功效。这种方式同样利用了 classloader 机制来保证初始化 instance 时只有一个线程

public class Singleton {  

    //静态内部类只有在被使用的时候才会初始化
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();  
    }  

    private Singleton (){}  

    public static final Singleton getInstance() { 

        return SingletonHolder.INSTANCE;  
    }  
}

6.枚举

这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。枚举类在类加载的时候会初始化里面所有的实例,而且JVM保证它们不会被实例化,所以天生是单例的。

public enum Singleton {  
    //枚举类确保每一个列对象在全局是唯一的。
    INSTANCE;  
    public void whateverMethod() {  
    }  
}

总结

懒汉式和饿汉式的根本区别在于是否在类内方法外创建自己的对象,同时声明对象私有化,构造方法私有化,从而外部不能通过new对象的方式来访问。而饿汉式的话是声明并且创建对象,懒汉式只是声明对象,在调用该类的getInstance()方法时才会进行new对象。

本文标题:设计模式 - 单例

文章作者:Bangjin-Hu

发布时间:2019年10月15日 - 09:22:26

最后更新:2020年03月30日 - 08:21:16

原始链接:http://bangjinhu.github.io/undefined/设计模式 - 单例模式/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Bangjin-Hu wechat
欢迎扫码关注微信公众号,订阅我的微信公众号.
坚持原创技术分享,您的支持是我创作的动力.